package service

import (
	"context"
	"time"

	"github.com/mars/internal/admin/core/domain"
	"github.com/mars/pkg/errors"
	"github.com/mars/pkg/loggers"
)

// BookingSrv 预约服务接口
type BookingSrv interface {
	// GetBookingList 获取预约列表
	GetBookingList(ctx context.Context, params domain.BookingQueryParams) ([]domain.Booking, int64, error)

	// GetBookingDetail 获取预约详情
	GetBookingDetail(ctx context.Context, bookingID string) (*domain.Booking, error)

	// ConfirmBooking 确认预约
	ConfirmBooking(ctx context.Context, bookingID string) error

	// RejectBooking 拒绝预约
	RejectBooking(ctx context.Context, bookingID string, reason string) error

	// CancelBooking 取消预约
	CancelBooking(ctx context.Context, bookingID string, reason string) error

	// CompleteBooking 完成预约
	CompleteBooking(ctx context.Context, bookingID string) error

	// GetBookingStats 获取预约统计信息
	GetBookingStats(ctx context.Context) (*domain.BookingStats, error)

	// GetAvailableTimeSlots 获取可用时间段
	GetAvailableTimeSlots(ctx context.Context, venueType domain.VenueType, bookingDate int64) (*domain.AvailableSlots, error)
}

type bookingService struct {
	domain         domain.Factory
	bookingGateway domain.BookingGateway
}

var _ BookingSrv = (*bookingService)(nil)

func newBookingService(domain domain.Factory) *bookingService {
	return &bookingService{
		domain:         domain,
		bookingGateway: domain.BookingGateway(),
	}
}

// GetBookingList 获取预约列表
func (bs *bookingService) GetBookingList(ctx context.Context, params domain.BookingQueryParams) ([]domain.Booking, int64, error) {
	bookings, total, err := bs.bookingGateway.GetBookingList(ctx, params)
	if err != nil {
		loggers.Error(ctx, "get booking list failed", err)
		return nil, 0, err
	}
	return bookings, total, nil
}

// GetBookingDetail 获取预约详情
func (bs *bookingService) GetBookingDetail(ctx context.Context, bookingID string) (*domain.Booking, error) {
	if bookingID == "" {
		return nil, errors.New(400, "booking ID is required")
	}

	booking, err := bs.bookingGateway.GetBooking(ctx, bookingID)
	if err != nil {
		loggers.Error(ctx, "get booking detail failed", err)
		return nil, err
	}
	return booking, nil
}

// ConfirmBooking 确认预约
func (bs *bookingService) ConfirmBooking(ctx context.Context, bookingID string) error {
	if bookingID == "" {
		return errors.New(400, "booking ID is required")
	}

	matched, err := bs.bookingGateway.UpdateBookingStatus(ctx, bookingID, domain.BookingStatusConfirmed, domain.BookingStatusPending, "")
	if err != nil {
		loggers.Error(ctx, "confirm booking failed", err)
		return err
	}
	if matched == 0 {
		return errors.NewFormatted(400, "未能找到预约: %s, 状态: %s", bookingID, domain.BookingStatusPending)
	}
	return nil
}

// RejectBooking 拒绝预约
func (bs *bookingService) RejectBooking(ctx context.Context, bookingID string, reason string) error {
	matched, err := bs.bookingGateway.UpdateBookingStatus(ctx, bookingID, domain.BookingStatusRejected, domain.BookingStatusPending, reason)
	if err != nil {
		loggers.Error(ctx, "reject booking failed", err)
		return err
	}
	if matched == 0 {
		return errors.NewFormatted(400, "未能找到预约: %s, 状态: %s", bookingID, domain.BookingStatusPending)
	}
	return nil
}

// CancelBooking 取消预约
func (bs *bookingService) CancelBooking(ctx context.Context, bookingID string, reason string) error {
	if bookingID == "" {
		return errors.New(400, "booking ID is required")
	}

	if reason == "" {
		return errors.New(400, "取消原因不能为空")
	}

	// 获取预约信息，验证状态
	booking, err := bs.bookingGateway.GetBooking(ctx, bookingID)
	if err != nil {
		loggers.Error(ctx, "get booking for cancel failed", err)
		return err
	}

	// 只有待确认或已确认状态的预约才能取消
	if booking.Status != domain.BookingStatusPending && booking.Status != domain.BookingStatusConfirmed {
		return errors.New(400, "只有待确认或已确认状态的预约才能取消")
	}

	err = bs.bookingGateway.CancelBooking(ctx, bookingID, reason)
	if err != nil {
		loggers.Error(ctx, "cancel booking failed", err)
		return err
	}
	return nil
}

// CompleteBooking 完成预约
func (bs *bookingService) CompleteBooking(ctx context.Context, bookingID string) error {
	matched, err := bs.bookingGateway.UpdateBookingStatus(ctx, bookingID, domain.BookingStatusCompleted, domain.BookingStatusConfirmed, "")
	if err != nil {
		loggers.Error(ctx, "complete booking failed", err)
		return err
	}
	if matched == 0 {
		return errors.NewFormatted(400, "未能找到预约: %s, 状态: %s", bookingID, domain.BookingStatusConfirmed)
	}
	return nil
}

// GetBookingStats 获取预约统计信息
func (bs *bookingService) GetBookingStats(ctx context.Context) (*domain.BookingStats, error) {
	stats, err := bs.bookingGateway.GetBookingStats(ctx)
	if err != nil {
		loggers.Error(ctx, "get booking stats failed", err)
		return nil, err
	}
	return stats, nil
}

// GetAvailableTimeSlots 获取可用时间段
func (bs *bookingService) GetAvailableTimeSlots(ctx context.Context, venueType domain.VenueType, bookingDate int64) (*domain.AvailableSlots, error) {
	if venueType == "" {
		return nil, errors.New(400, "venue type is required")
	}

	if bookingDate == 0 {
		return nil, errors.New(400, "booking date is required")
	}

	// 不能查询过去的日期
	now := time.Now()
	todayTimestamp := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Unix()
	if bookingDate < todayTimestamp {
		return nil, errors.New(400, "不能查询过去的日期")
	}

	slots, err := bs.bookingGateway.GetAvailableTimeSlots(ctx, venueType, bookingDate)
	if err != nil {
		loggers.Error(ctx, "get available time slots failed", err)
		return nil, err
	}
	return slots, nil
}
